﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using Kokomo.Mirror.CliMetadata;
using Kokomo.Mirror.Ia32;
using Kokomo.Mirror.PeFormat.Resources;
using Kokomo.Mirror.PeFormat.Symbols;
using System.Globalization;
using System.Threading;

namespace Kokomo.Mirror.PeFormat
{
	public class PeModule
	{
		internal const int IMAGE_OS2_SIGNATURE = 0x454E;      // NE
		internal const int IMAGE_OS2_SIGNATURE_LE = 0x454C;   // LE
		internal const int IMAGE_VXD_SIGNATURE = 0x454C;      // LE
		internal const int IMAGE_NT_SIGNATURE = 0x00004550;   // PE00

		public static readonly string LayoutCategoryName = "Layout";
		public static readonly string StateCategoryName = "State";
		public static readonly string PlatformCategoryName = "Platform";
		public static readonly string MemoryCategoryName = "Memory";

		public static PeModule Open(
			string fileName
			)
		{
			return Open(fileName, PeModuleLoadOptions.LoadModule);
		}
		public static PeModule Open(
			string fileName,
			PeModuleLoadOptions options
			)
		{
			if (fileName == null) throw new ArgumentNullException("FileName");

			PeModule pe = new PeModule(fileName);
			if (options.HasFlag(PeModuleLoadOptions.LoadModule))
			{
				byte[] allBytes;
				using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
				{
					allBytes = new byte[stream.Length];
					stream.Read(allBytes, 0, allBytes.Length);
				}
				pe._allBytes = allBytes;
			}

			using (Stream stream = pe.GetStream())
			{
				StructSerializer serializer = new StructSerializer();

				PeFileLayout layout = new PeFileLayout();
				pe.FileLayout = layout;

				DosHeader dosHeader = serializer.ReadStruct<DosHeader>(stream);
				pe.DosHeader = dosHeader;
				if (!dosHeader.IsMagicValid)
					throw new BadImageFormatException("Invalid DOS header magic");
				if (dosHeader.NewExeHeaderOffset == 0)
					throw new BadImageFormatException("Image does not contain new EXE header");

				layout.NewExeHeaderOffset = dosHeader.NewExeHeaderOffset;

				stream.Position = layout.NewExeHeaderOffset;
				BinaryReader reader = new BinaryReader(stream);
				NewExeFileHeader newExeHeader = serializer.ReadStruct<NewExeFileHeader>(stream);
				if (newExeHeader.Signature != NewExeFileHeader.PeSignature)
					throw new BadImageFormatException("New EXE file header does not contain PE signature");
				pe.NewExeFileHeader = newExeHeader;

				PeModuleType moduleType = PeModuleType.Unknown;
				IOptionalHeader optionalHeader = null;
				layout.OptionalHeaderOffset = (uint)stream.Position;
				if (newExeHeader.SizeOfOptionalHeader == OptionalHeader32.StructSize)
				{
					optionalHeader = serializer.ReadStruct<OptionalHeader32>(stream);
					moduleType = PeModuleType.Pe32;
				}
				else if (newExeHeader.SizeOfOptionalHeader == OptionalHeader64.StructSize)
				{
					optionalHeader = serializer.ReadStruct<OptionalHeader64>(stream);
					moduleType = PeModuleType.Pe32Plus;
				}
				else
				{
					throw new BadImageFormatException("Unrecognized optional header");
				}
				pe.OptionalHeader = optionalHeader;
				pe.ModuleType = moduleType;

				layout.SectionHeaderTableOffset = (uint)stream.Position;
				SectionHeader[] sectionHeaders = serializer.ReadArray<SectionHeader>(newExeHeader.NumberOfSections, stream);
				pe.SectionHeaders = sectionHeaders;

				DataDirectoryEntry cliDirectoryEntry = pe.GetDirectoryEntry(DataDirectoryNumber.ComRuntimeDescriptor);
				if (cliDirectoryEntry != null)
				{
					layout.Cor20HeaderOffset = pe.RvaToFileOffset(cliDirectoryEntry.VirtualAddress).Value;
					stream.Position = layout.Cor20HeaderOffset;

					Cor20Header cor20Header = serializer.ReadStruct<Cor20Header>(stream);
					if (cor20Header.IsStructSizeValid)
					{
						pe.Cor20Header = cor20Header;

						layout.CliMetadataRootOffset = pe.RvaToFileOffset(cor20Header.MetaData.VirtualAddress).Value;
						stream.Position = layout.CliMetadataRootOffset;

						Cor20MetadataRootHeader metadataRootHeader = serializer.ReadStruct<Cor20MetadataRootHeader>(stream);
						if (metadataRootHeader.IsSignatureValid)
						{
							pe.Cor20MetadataRootHeader = metadataRootHeader;

							Cor20StreamHdr metadataStream = pe.GetCliStreamHeader(CliStreamNames.MetadataStreamName);

							if (metadataStream != null)
							{
								stream.Position = metadataStream.Offset + layout.CliMetadataRootOffset;
								Cor20MetadataStreamHeader metadataStreamHeader = serializer.ReadStruct<Cor20MetadataStreamHeader>(stream);

								pe.Cor20MetadataStreamHeader = metadataStreamHeader;

								pe.IsCliAssembly = true;
							}
						}
					}
				}
			}

			pe.PopulateNameTable();

			//if (loadBaseAddress.HasValue)
			//    pe.LoadBaseAddress = loadBaseAddress.Value;
			//else
			pe.LoadBaseAddress = pe.OptionalHeader.ImageBase;

			return pe;
		}

		protected PeModule(
			string fileName
			)
		{
			this.FileName = fileName;
			this._exportDirectory = new Lazy<ExportDirectory>(this.LoadExportDirectory);
			this._importDirectory = new Lazy<ImportDirectory>(this.LoadImportDirectory);
			this._resourceRootDirectory = new Lazy<ResourceDirectory>(this.LoadResources);
			this._metadataContainer = new Lazy<MetadataContainer>(this.LoadCliMetadata);
		}

		public string FileName { get; private set; }

		public PeModuleType ModuleType { get; private set; }

		#region Headers
		public DosHeader DosHeader { get; private set; }
		public NewExeFileHeader NewExeFileHeader { get; private set; }
		public IOptionalHeader OptionalHeader { get; private set; }
		public SectionHeader[] SectionHeaders { get; private set; }
		#endregion

		#region Layout
		public PeFileLayout FileLayout { get; private set; }
		public uint? RvaToFileOffset(uint rva)
		{
			SectionHeader section = this.FindSectionContainingRva(rva);
			if (section == null) return null;

			uint offset = rva - section.VirtualAddress + section.PointerToRawData;

			return offset;
		}
		public SectionHeader FindSectionByName(string name)
		{
			if (name == null) throw new ArgumentNullException("name");
			if (this.SectionHeaders == null) throw new InvalidOperationException("Sections not loaded");

			foreach (var sectionHeader in this.SectionHeaders)
			{
				if (sectionHeader.Name == name) return sectionHeader;
			}

			return null;
		}
		public SectionHeader FindSectionContainingRva(uint rva)
		{
			if (this.SectionHeaders == null) throw new InvalidOperationException("Sections not loaded");

			foreach (var section in this.SectionHeaders)
			{
				if (section.Contains(rva))
				{
					return section;
				}
			}

			return null;
		}
		public long LoadBaseAddress { get; private set; }

		public long RvaToAbsolute(uint rva)
		{
			return rva + this.LoadBaseAddress;
		}

		public uint AbsoluteToRva(long absolute)
		{
			return (uint)(absolute - this.LoadBaseAddress);
		}

		public bool IsValidAddress(long absoluteAddress)
		{
			long rva = absoluteAddress - this.LoadBaseAddress;
			if (rva < 0) return false;
			return this.IsValidRva((uint)rva);
		}
		public bool IsValidRva(uint rva)
		{
			SectionHeader header = this.FindSectionContainingRva(rva);

			return (header != null);
		}
		#endregion

		#region Data directory
		public bool HasDirectoryEntry(DataDirectoryNumber number)
		{
			return this.GetDirectoryEntry(number) != null;
		}
		public DataDirectoryEntry GetDirectoryEntry(DataDirectoryNumber number)
		{
			int index = (int)number;
			DataDirectoryEntry[] entries = this.OptionalHeader.DataDirectory;
			if (index >= entries.Length)
				return null;

			DataDirectoryEntry entry = entries[index];
			if (entry.VirtualAddress == 0)
				return null;

			return entry;
		}

		public bool HasExportDirectory { get { return this.HasDirectoryEntry(DataDirectoryNumber.ExportDirectory); } }
		public bool HasImportDirectory { get { return this.HasDirectoryEntry(DataDirectoryNumber.ImportDirectory); } }

		public DataDirectoryEntry ExportDirectoryEntry { get { return this.GetDirectoryEntry(DataDirectoryNumber.ExportDirectory); } }
		public DataDirectoryEntry ImportDirectoryEntry { get { return this.GetDirectoryEntry(DataDirectoryNumber.ImportDirectory); } }
		public DataDirectoryEntry DelayLoadImportDirectoryEntry { get { return this.GetDirectoryEntry(DataDirectoryNumber.DelayLoadImportDescriptors); } }
		public DataDirectoryEntry ResourceDataDirectoryEntry { get { return this.GetDirectoryEntry(DataDirectoryNumber.ResourceDirectory); } }
		#endregion

		public bool Is64Bit
		{
			get { return this.ModuleType == PeModuleType.Pe32Plus; }
		}
		public bool Is32Bit
		{
			get { return this.ModuleType == PeModuleType.Pe32; }
		}

		public IaDisassembler GetDisassembler()
		{
			if (this.Is64Bit)
				return IaDisassembler.Disassembler64;
			else if (this.Is32Bit)
				return IaDisassembler.Disassembler32;

			return null;
		}

		#region Exports
		private Lazy<ExportDirectory> _exportDirectory;
		public ExportDirectory ExportDirectory { get { return this._exportDirectory.Value; } }

		private ExportDirectory LoadExportDirectory()
		{
			if (this.ExportDirectoryEntry == null) return null;
			return ExportDirectory.LoadFromModule(this);
		}
		#endregion
		#region Imports
		private Lazy<ImportDirectory> _importDirectory;
		private ImportDirectory LoadImportDirectory()
		{
			if (this.ImportDirectoryEntry == null) return null;
			return ImportDirectory.LoadFromModule(this);
		}
		public ImportDirectory ImportDirectory { get { return this._importDirectory.Value; } }
		#endregion
		#region Resources
		private Lazy<ResourceDirectory> _resourceRootDirectory;
		public ResourceDirectory ResourceRootDirectory { get { return this._resourceRootDirectory.Value; } }
		private ResourceDirectory EnumerateResourceDirectory(
			Stream stream,
			uint rva,
			ResourcePath parentPath
			)
		{
			StructSerializer serializer = new StructSerializer(Encoding.Unicode);

			ResourceDirectoryHeader directoryHeader = serializer.ReadStruct<ResourceDirectoryHeader>(stream);
			ResourceDirectoryEntry[] directoryEntries = serializer.ReadArray<ResourceDirectoryEntry>(directoryHeader.NumberOfNamedEntries + directoryHeader.NumberOfIdEntries, stream);
			List<ResourceItem> resources = new List<ResourceItem>();

			foreach (var entry in directoryEntries)
			{
				ResourcePathPart pathPart;
				if (entry.HasName)
				{
					stream.Position = this.RvaToFileOffset(rva + (entry.NameOrId & ~ResourceDirectoryEntry.NameFlag)).Value;
					ResourceDirectoryString stringStruct = serializer.ReadStruct<ResourceDirectoryString>(stream);
					pathPart = new ResourceNamePart(stringStruct.Name);
				}
				else
				{
					pathPart = new ResourceIdPart((short)entry.NameOrId);
				}

				ResourcePath path =
					(parentPath == null)
					? new ResourcePath(pathPart)
					: parentPath.Concat(pathPart)
					;
				uint fileOffset = this.RvaToFileOffset(rva + (entry.Offset & ~0x80000000)).Value;
				if (entry.IsDirectory)
				{
					stream.Position = fileOffset;
					ResourceDirectory childDirectory = EnumerateResourceDirectory(
						stream,
						rva,
						path
						);
					resources.Add(childDirectory);
				}
				else
				{
					stream.Position = fileOffset;
					ResourceDataEntry dataEntry = serializer.ReadStruct<ResourceDataEntry>(stream);
					ResourceDataDescriptor resource = new ResourceDataDescriptor(
						this,
						path,
						(uint)dataEntry.OffsetToData, //(uint)(rva + dataEntry.OffsetToData),
						dataEntry.Size,
						dataEntry.CodePage
						);
					resources.Add(resource);
				}
			}

			ResourceDirectory directory = new ResourceDirectory(this, parentPath, resources);
			return directory;
		}
		private ResourceDirectory LoadResources()
		{
			if (this.ResourceDataDirectoryEntry == null) return null;

			using (Stream stream = this.GetStream())
			{
				DataDirectoryEntry resourceDirectory = this.OptionalHeader.DataDirectory[(int)DataDirectoryNumber.ResourceDirectory];
				uint origin = this.RvaToFileOffset(resourceDirectory.VirtualAddress).Value;
				stream.Position = origin;

				ResourceDirectory rootDirectory = EnumerateResourceDirectory(stream, resourceDirectory.VirtualAddress, new ResourcePath());
				return rootDirectory;
			}
		}
		#endregion
		#region CLI headers
		public bool IsCliAssembly { get; private set; }

		public Cor20Header Cor20Header { get; private set; }
		public Cor20MetadataRootHeader Cor20MetadataRootHeader { get; private set; }
		public Cor20MetadataStreamHeader Cor20MetadataStreamHeader { get; private set; }

		public Cor20StreamHdr GetCliStreamHeader(string name)
		{
			if (name == null) throw new ArgumentNullException("name");

			if (this.Cor20MetadataRootHeader == null)
				return null;

			return this.Cor20MetadataRootHeader.GetStreamHeader(name);
		}

		private Lazy<MetadataContainer> _metadataContainer;
		private MetadataContainer LoadCliMetadata()
		{
			if (!this.IsCliAssembly) return null;

			Cor20MetadataStreamHeader metadataStreamHeader = this.Cor20MetadataStreamHeader;

			PeFileLayout layout = this.FileLayout;
			MetadataContainer container;
			using (Stream stream = this.GetStream())
			{
				StructSerializer serializer = new StructSerializer();

				Cor20MetadataRootHeader rootHeader = this.Cor20MetadataRootHeader;

				byte[] stringData;
				{
					Cor20StreamHdr stringStreamHeader = rootHeader.GetStreamHeader(CliStreamNames.StringStreamName);
					uint stringHeapOffset = layout.CliMetadataRootOffset + stringStreamHeader.Offset;
					uint stringHeapSize = stringStreamHeader.Size;
					stringData = new byte[stringHeapSize];
					stream.Position = stringHeapOffset;
					stream.Read(stringData, 0, (int)stringHeapSize);
				}
				byte[] userStringData;
				{
					Cor20StreamHdr userStringStreamHeader = rootHeader.GetStreamHeader(CliStreamNames.UserStringStreamName);
					if (userStringStreamHeader != null)
					{
						uint stringHeapOffset = layout.CliMetadataRootOffset + userStringStreamHeader.Offset;
						uint stringHeapSize = userStringStreamHeader.Size;
						userStringData = new byte[stringHeapSize];
						stream.Position = stringHeapOffset;
						stream.Read(userStringData, 0, (int)stringHeapSize);
					}
					else
					{
						userStringData = new byte[0];
					}
				}
				byte[] blobData;
				{
					Cor20StreamHdr blobStreamHeader = rootHeader.GetStreamHeader(CliStreamNames.BlobStreamName);
					if (blobStreamHeader != null)
					{
						uint heapOffset = layout.CliMetadataRootOffset + blobStreamHeader.Offset;
						uint heapSize = blobStreamHeader.Size;
						blobData = new byte[heapSize];
						stream.Position = heapOffset;
						stream.Read(blobData, 0, (int)heapSize);
					}
					else
					{
						blobData = new byte[0];
					}
				}
				byte[] guidData;
				{
					Cor20StreamHdr guidStreamHeader = rootHeader.GetStreamHeader(CliStreamNames.GuidStreamName);
					uint heapOffset = layout.CliMetadataRootOffset + guidStreamHeader.Offset;
					uint heapSize = guidStreamHeader.Size;
					guidData = new byte[heapSize];
					stream.Position = heapOffset;
					stream.Read(guidData, 0, (int)heapSize);
				}

				container = new MetadataContainer(
					metadataStreamHeader.HasLargeStringHeap,
					stringData,
					true,
					userStringData,
					metadataStreamHeader.HasLargeBlobHeap,
					blobData,
					metadataStreamHeader.HasLargeGuidHeap,
					guidData,
					MetadataOptions.ResolveInvalidStringsToNull | MetadataOptions.ResolveInvalidUserStringsToNull | MetadataOptions.ResolveInvalidBlobsToNull
					);

				stream.Position = metadataStreamHeader.DataOffset;// +layout.CliMetadataRootOffset;
				MetadataReader metadataReader = new MetadataReader(stream, container, MetadataReaderOptions.AllowInvalidIndex);
				try
				{
					for (int tableIndex = 0; tableIndex < metadataStreamHeader.TableCount; tableIndex++)
					{
						MetadataTableNumber tableNumber = metadataStreamHeader.TableNumbers[tableIndex];
						int rowCount = (int)metadataStreamHeader.Rows[tableIndex];

						MetadataTable table = container.GetTable(tableNumber);
						table.Populate(rowCount);

						metadataReader.ReadTable(table);
					}
				}
				catch { }
			}

			return container;
		}

		public MetadataContainer MetadataContainer { get { return this._metadataContainer.Value; } }
		#endregion

		#region Names and Symbols
		private Dictionary<string, uint> _nameTable;
		private Dictionary<uint, SymbolicReference> _namesByRva;
		private void PopulateNameTable()
		{
			Dictionary<uint, SymbolicReference> namesByRva = new Dictionary<uint, SymbolicReference>();
			Dictionary<string, uint> nameTable = new Dictionary<string, uint>();
			if (this.ExportDirectory != null)
			{
				foreach (var export in this.ExportDirectory.Exports)
				{
					if (export.DecoratedName != null)
					{
						namesByRva[export.Rva] = new SymbolicReference(export.DecoratedName, 0);
						nameTable[export.DecoratedName] = export.Rva;
					}
				}
			}
			if (this.ImportDirectory != null)
			{
				foreach (var importedModule in this.ImportDirectory.ImportedModules)
				{
					foreach (var importedFunction in importedModule.Functions)
					{
						string functionName = importedFunction.DecoratedName ?? "#" + importedFunction.Ordinal;
						namesByRva[importedFunction.ThunkRva] = new SymbolicReference(
							functionName,
							0,
							importedModule.ModuleName
							);
					}
				}
			}

			this._namesByRva = namesByRva;
			this._nameTable = nameTable;
		}

		public SymbolicReference LookupSymbolicReference(uint rva)
		{
			SymbolicReference reference;
			this._namesByRva.TryGetValue(rva, out reference);

			return reference;
		}
		public uint ResolveExportName(string exportName)
		{
			if (exportName == null) throw new ArgumentNullException("exportName");

			uint rva;
			this._nameTable.TryGetValue(exportName, out rva);
			return rva;
		}
		//public NativeProcedureInfo GetProcedure(string name)
		//{
		//    uint rva = this.ResolveName(name);
		//    if (rva == 0) return null;
		//    return this.GetProcedureAtRva(rva);
		//}
		public NativeProcedureInfo GetProcedureAtRva(uint rva)
		{
			NativeProcedureInfo procedureInfo = new NativeProcedureInfo(
				this,
				rva,
				null
				);

			return procedureInfo;
		}

		public string ResolveModule(string moduleName)
		{
			if (moduleName == null) throw new ArgumentNullException("moduleName");

			bool safeSearchMode = false;

			IEnumerable<string> searchPaths = new string[] {
				Path.GetDirectoryName(this.FileName),
				Environment.SystemDirectory,
				// 16-bit system directory
				Environment.GetFolderPath(Environment.SpecialFolder.Windows),
				// Current firectory
			}.Concat(Environment.GetEnvironmentVariable("path").Split(';'));

			foreach (var directory in searchPaths)
			{
				string fileName = Path.Combine(directory, moduleName);
				if (File.Exists(fileName)) return fileName;
			}

			return null;
		}
		#endregion

		#region I/O
		private byte[] _allBytes;
		public Stream GetStream()
		{
			byte[] data = this._allBytes;
			if (data != null)
				return new MemoryStream(data);
			else
				return new FileStream(this.FileName, FileMode.Open, FileAccess.Read);
		}

		public void Unload()
		{
			this._allBytes = null;
		}

		public byte[] ReadSectionData(string sectionName)
		{
			if (sectionName == null) throw new ArgumentNullException("sectionName");
			SectionHeader sectionHeader = this.FindSectionByName(sectionName);
			if (sectionHeader == null) throw new ArgumentException("Invalid section name");

			byte[] data = new byte[sectionHeader.SizeOfRawData];
			using (Stream stream = this.GetStream())
			{
				stream.Position = sectionHeader.PointerToRawData;
				stream.Read(data, 0, (int)sectionHeader.SizeOfRawData);
			}

			return data;
		}

		public bool ReadInitializedData(
			uint rva,
			out int int32Value,
			out string stringValue
			)
		{

			int32Value = 0;
			stringValue = null;

			SectionHeader section = this.FindSectionContainingRva(rva);
			if (section == null) return false;

			uint offset = rva - section.VirtualAddress;
			byte[] sectionData = this.ReadSectionData(section.Name);
			int32Value = BitConverter.ToInt32(sectionData, (int)offset);

			MemoryStream sectionStream = new MemoryStream(sectionData);
			ScannedString? scannedString = StringScanner.TryReadString(sectionStream);
			if (scannedString.HasValue)
				stringValue = scannedString.Value.Text;

			return true;
		}
		#endregion

		//public IEnumerable<Ia32Disassembly> DiscoverProcedures()
		//{
		//    Queue<uint> procedureRvas = new Queue<uint>();
		//    Dictionary<long, Ia32Disassembly> procedureTable = new Dictionary<long, Ia32Disassembly>();
		//    Dictionary<long, string> nameTable = new Dictionary<long, string>();

		//    IOptionalHeader optionalHeader = this.Headers.OptionalHeader;
		//    long imageBaseAddress = optionalHeader.ImageBase;

		//    // Add entry point
		//    long entryPointBaseAddress = optionalHeader.AddressOfEntryPoint;
		//    if (entryPointBaseAddress != 0)
		//    {
		//        if (this.Headers.NewExeFileHeader.Characteristics.HasFlag(FileCharacteristics.DynamicLinkLibrary))
		//        {
		//            nameTable[entryPointBaseAddress] = "DllMain";
		//        }
		//        else
		//        {
		//            nameTable[entryPointBaseAddress] = "entryThunk";
		//        }

		//        procedureRvas.Enqueue((uint)entryPointBaseAddress);
		//    }

		//    // Add exports
		//    foreach (var export in this.ExportedFunctions)
		//    {
		//        if (!export.IsForwarded)
		//        {
		//            nameTable[export.Rva] = export.DecoratedName;
		//            procedureRvas.Enqueue(export.Rva);
		//        }
		//    }

		//    Dictionary<string, Stream> sectionStreams = new Dictionary<string, Stream>();

		//    List<Ia32Disassembly> procedures = new List<Ia32Disassembly>();
		//    SectionHeader section = null;
		//    while (procedureRvas.Count > 0)
		//    {
		//        uint procedureRva = procedureRvas.Dequeue();
		//        if (procedureTable.ContainsKey(procedureRva))
		//            continue;

		//        Stream sectionStream = null;
		//        if (
		//            (section == null)
		//            || (!section.Contains((uint)procedureRva))
		//            )
		//        {
		//            section = this.Headers.FindSectionContainingRva(procedureRva);

		//            if (section == null) continue;

		//        }
		//        if (!sectionStreams.TryGetValue(section.Name, out sectionStream))
		//        {
		//            byte[] sectionData = this.ReadSectionData(section.Name);
		//            sectionStream = new MemoryStream(sectionData);
		//            sectionStreams[section.Name] = sectionStream;
		//        }

		//        string name;
		//        nameTable.TryGetValue(procedureRva, out name);

		//        sectionStream.Position = (procedureRva - section.VirtualAddress);

		//        try
		//        {
		//            Ia32Disassembly disassembly = Ia32Disassembler.Disassemble(sectionStream, section.VirtualAddress + imageBaseAddress);
		//            if (procedure != null)
		//            {
		//                foreach (var dependency in procedure.Dependencies)
		//                {
		//                    if (dependency.Type == DependencyType.Procedure)
		//                    {
		//                        long dependentProcedureRva = dependency.VirtualAddress - imageBaseAddress;
		//                        procedureRvas.Enqueue((uint)dependentProcedureRva);
		//                    }
		//                }
		//                procedure.Name = name;

		//                procedures.Add(procedure);
		//            }
		//        }
		//        catch { }
		//    }

		//    return procedures;
		//}
	}
}
